home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / extras / Direct3D / Tools / 3DSMax4 / meshdata.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  21.4 KB  |  588 lines

  1. //-----------------------------------------------------------------------------
  2. // File: MeshData.cpp
  3. //
  4. // Desc: Functions used to massage mesh data into a format useable in X Files
  5. //
  6. // Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9. #include "pch.h"
  10. #include "MeshData.h"
  11.  
  12. BOOL FindIdenticalVertex
  13.     (
  14.     SMeshData *pMeshData, 
  15.     DWORD iVertexIndex, 
  16.     DWORD iSmoothingGroup, 
  17.     DWORD iTextureIndex,
  18.     DWORD iMaterial,
  19.     DWORD *piVertex
  20.     )
  21. {
  22.     DWORD iHeadVertex;
  23.     DWORD iCurVertex;
  24.  
  25.     // walk the wedge list to see if any of the other vertice have the same smoothing and texture index
  26.     iHeadVertex = iVertexIndex;
  27.     iCurVertex = iHeadVertex;
  28.     do
  29.     {
  30.         // if identical requirements, then return true with the vertex index
  31.         if ((pMeshData->m_rgVertices[iCurVertex].iSmoothingGroupIndex == iSmoothingGroup)
  32.             && (pMeshData->m_rgVertices[iCurVertex].iTextureIndex == iTextureIndex) 
  33.             && (pMeshData->m_rgVertices[iCurVertex].iMaterial == iMaterial) )
  34.         {
  35.             *piVertex = iCurVertex;
  36.             return TRUE;
  37.         }
  38.  
  39.         // move to next element of wedge list and check to see if we wrapped (circular list)
  40.         iCurVertex = pMeshData->m_rgVertices[iCurVertex].iWedgeList;
  41.     }
  42.     while (iHeadVertex != iCurVertex);
  43.  
  44.     return FALSE;
  45. }
  46.  
  47. void FindNormal
  48.     (
  49.     SMeshData *pMeshData,
  50.     DWORD iVertexIndex, 
  51.     DWORD iSmoothingGroup,
  52.     Point3 &vNormalNew 
  53.     )
  54. {
  55.     DWORD iHeadVertex;
  56.     DWORD iCurVertex;
  57.  
  58.     // walk the wedge list to find other split vertices with the same smoothing group
  59.     iHeadVertex = iVertexIndex;
  60.     iCurVertex = iHeadVertex;
  61.     do
  62.     {
  63.         // if same smoothing group add the normal in
  64.         if (pMeshData->m_rgVertices[iCurVertex].iSmoothingGroupIndex == iSmoothingGroup)    
  65.         {
  66.             vNormalNew = pMeshData->m_rgVertices[iCurVertex].vNormal;
  67.             return;
  68.         }
  69.  
  70.         // move to next element of wedge list and check to see if we wrapped (circular list)
  71.         iCurVertex = pMeshData->m_rgVertices[iCurVertex].iWedgeList;
  72.     }
  73.     while (iHeadVertex != iCurVertex);
  74.  
  75.     //.first vertex in the smoothing group, set normal to zero
  76.     vNormalNew.x = 0.0f;
  77.     vNormalNew.y = 0.0f;
  78.     vNormalNew.z = 0.0f;
  79. }
  80.  
  81. void AddNormalContribution
  82.     (
  83.     SMeshData *pMeshData,
  84.     DWORD iVertexIndex, 
  85.     DWORD iSmoothingGroup,
  86.     Point3 vNormal 
  87.     )
  88. {
  89.     DWORD iHeadVertex;
  90.     DWORD iCurVertex;
  91.  
  92.     // walk the wedge list to find other split vertices with the same smoothing group
  93.     iHeadVertex = iVertexIndex;
  94.     iCurVertex = iHeadVertex;
  95.     do
  96.     {
  97.         // if same smoothing group add the normal in
  98.         if (pMeshData->m_rgVertices[iCurVertex].iSmoothingGroupIndex == iSmoothingGroup)    
  99.         {
  100.             pMeshData->m_rgVertices[iCurVertex].vNormal += vNormal;
  101.         }
  102.  
  103.         // move to next element of wedge list and check to see if we wrapped (circular list)
  104.         iCurVertex = pMeshData->m_rgVertices[iCurVertex].iWedgeList;
  105.     }
  106.     while (iHeadVertex != iCurVertex);
  107.  
  108. }
  109.  
  110. HRESULT GenerateMeshData
  111.     (
  112.     Mesh *pMesh,
  113.     SMeshData *pMeshData,
  114.     DWORD *rgdwMeshMaterials
  115.     )
  116. {
  117.     HRESULT hr = S_OK;
  118.     BOOL *rgbVertexReferencedArray = NULL;
  119.     DWORD cVerticesMax;
  120.     DWORD iRawVertexIndex;
  121.     DWORD iTextureIndex;
  122.     DWORD iSmoothingGroupIndex;
  123.     DWORD iVertex;
  124.     DWORD iFace;
  125.     DWORD iPoint;
  126.     DWORD iNewVertex;
  127.     BOOL bFound;
  128.     SVertexData *rgVerticesNew;
  129.     DWORD iMaterial;
  130.  
  131.     assert(pMesh != NULL);
  132.     assert(pMeshData != NULL);
  133.  
  134.     pMeshData->m_bTexCoordsPresent = FALSE;
  135.     pMeshData->m_cFaces = pMesh->numFaces;
  136.     pMeshData->m_cVertices = pMesh->numVerts;
  137.     pMeshData->m_cVerticesBeforeDuplication = pMesh->numVerts;
  138.     cVerticesMax = pMesh->numVerts;
  139.  
  140.     pMeshData->m_rgVertices = new SVertexData[cVerticesMax];
  141.     pMeshData->m_rgFaces = new SFaceData[pMeshData->m_cFaces];
  142.     rgbVertexReferencedArray = new BOOL[pMeshData->m_cVerticesBeforeDuplication];
  143.  
  144.     if ((pMeshData ->m_rgVertices == NULL) 
  145.             || (pMeshData ->m_rgFaces == NULL)
  146.             || (rgbVertexReferencedArray == NULL))
  147.     {
  148.         hr = E_OUTOFMEMORY;
  149.         goto e_Exit;
  150.     }
  151.  
  152.     if( !(pMesh->normalsBuilt) )
  153.     {
  154.         pMesh->checkNormals(TRUE);
  155.     }
  156.  
  157.     // Initialize vertex node list so that first batch are the same as the
  158.     // vertex array in the mesh.  Duplicated vertices will be appended to the list.
  159.     // The first time a vertex comes up in face enumeration below, the initial vertex
  160.     // node added here will be modified to reflect the smoothing and texture info.
  161.     // When the vertex comes up again with different smoothing or texture info, the
  162.     // vertex will be duplicated and appended to the list.
  163.     for (iVertex = 0; iVertex < pMeshData->m_cVertices; iVertex++ )
  164.     {
  165.         rgbVertexReferencedArray[iVertex] = FALSE;
  166.  
  167.         pMeshData->m_rgVertices[iVertex].iPointRep = iVertex;
  168.         pMeshData->m_rgVertices[iVertex].iWedgeList = iVertex;
  169.  
  170.         // default values that should be reset if the vertex is actually used by a face...
  171.         pMeshData->m_rgVertices[iVertex].vNormal.x = 0;
  172.         pMeshData->m_rgVertices[iVertex].vNormal.y = 0;
  173.         pMeshData->m_rgVertices[iVertex].vNormal.z = 0;
  174.         pMeshData->m_rgVertices[iVertex].iSmoothingGroupIndex = 0;
  175.         pMeshData->m_rgVertices[iVertex].iTextureIndex = 0;
  176.         pMeshData->m_rgVertices[iVertex].iMaterial = 0;
  177.     }
  178.     
  179.     // for each face, add the face normal for each corner to the vertex node list array.
  180.     // The index into the vertex node list array is just the vertex index, and a list of CVertexNodes
  181.     // is built for the unique smoothing groups for that vertex.  Each CVertexNode holds the normal
  182.     // at that vertex based on a particular smoothing group.  All CVertexNodes get an index, and
  183.     // the list of CFaceIndices is a face list with the corners updated with the new expanded vertex
  184.     // indices (CVertexNode index).
  185.     //
  186.     // Added: Now CVertexNodes each represent a unique smoothing group + texture coordinate set
  187.     // for a vertex.
  188.     for( iFace = 0; iFace < pMeshData->m_cFaces; iFace++ )
  189.     {
  190.         for( iPoint = 0; iPoint < 3; iPoint++ ) // vertex indices
  191.         {
  192.             iRawVertexIndex = pMesh->faces[iFace].v[iPoint];
  193.             iTextureIndex = 0xFFFFFFFF;
  194.             iSmoothingGroupIndex = pMesh->faces[iFace].smGroup;
  195.             iMaterial = rgdwMeshMaterials[iFace];
  196.  
  197.             if ((pMesh->faces[iFace].flags & HAS_TVERTS) 
  198.                     && (NULL != pMesh->tvFace)
  199.                     && ((int)pMesh->tvFace[iFace].t[iPoint] < pMesh->numTVerts) )
  200.             {
  201.                 pMeshData->m_bTexCoordsPresent = TRUE;
  202.  
  203.                 iTextureIndex = pMesh->tvFace[iFace].t[iPoint];
  204.             }
  205.             
  206.             if (FALSE == rgbVertexReferencedArray[iRawVertexIndex])
  207.             {
  208.                 // first reference to this vertex.
  209.                 rgbVertexReferencedArray[iRawVertexIndex] = TRUE;
  210.  
  211.                 pMeshData->m_rgVertices[iRawVertexIndex].iSmoothingGroupIndex = iSmoothingGroupIndex;
  212.                 pMeshData->m_rgVertices[iRawVertexIndex].iTextureIndex = iTextureIndex;
  213.                 pMeshData->m_rgVertices[iRawVertexIndex].iMaterial = iMaterial;
  214.  
  215.                 pMeshData->m_rgFaces[iFace].index[iPoint] = iRawVertexIndex;
  216.             }
  217.             else
  218.             {
  219.                 // need to remember the index
  220.                 bFound = FindIdenticalVertex(pMeshData, iRawVertexIndex, iSmoothingGroupIndex, iTextureIndex, iMaterial, &iNewVertex);
  221.  
  222.                 // if not found, then split out another vertex
  223.                 if (!bFound)
  224.                 {
  225.                     // realloc if array too small
  226.                     if (pMeshData->m_cVertices == cVerticesMax)
  227.                     {
  228.                         cVerticesMax = cVerticesMax * 2;
  229.                         rgVerticesNew = new SVertexData[cVerticesMax];
  230.                         if (rgVerticesNew == NULL)
  231.                         {
  232.                             hr = E_OUTOFMEMORY;
  233.                             goto e_Exit;
  234.                         }
  235.  
  236.                         memcpy(rgVerticesNew, pMeshData->m_rgVertices, sizeof(SVertexData) * pMeshData->m_cVertices);
  237.  
  238.                         delete []pMeshData->m_rgVertices;
  239.                         pMeshData->m_rgVertices = rgVerticesNew;
  240.                     }
  241.  
  242.                     // grab the next spot in the array
  243.                     iNewVertex = pMeshData->m_cVertices;
  244.                     pMeshData->m_cVertices += 1;
  245.  
  246.                     // setup point rep and wedge list
  247.                     pMeshData->m_rgVertices[iNewVertex].iPointRep = iRawVertexIndex;
  248.  
  249.                     // link into wedge list of point rep
  250.                     pMeshData->m_rgVertices[iNewVertex].iWedgeList = pMeshData->m_rgVertices[iRawVertexIndex].iWedgeList;
  251.                     pMeshData->m_rgVertices[iRawVertexIndex].iWedgeList = iNewVertex;
  252.  
  253.                     // setup vertex info
  254.                     pMeshData->m_rgVertices[iNewVertex].iSmoothingGroupIndex = iSmoothingGroupIndex;
  255.                     pMeshData->m_rgVertices[iNewVertex].iTextureIndex = iTextureIndex;
  256.                     pMeshData->m_rgVertices[iNewVertex].iMaterial = iMaterial;
  257.  
  258.                     // set normal to 0 if first vertex in a new smoothing group, otherwise set to the same value as 
  259.                     //   one of the other vertices in the same smoothing group
  260.                     FindNormal(pMeshData, iRawVertexIndex, iSmoothingGroupIndex, pMeshData->m_rgVertices[iNewVertex].vNormal);
  261.                 }
  262.  
  263.                 pMeshData->m_rgFaces[iFace].index[iPoint] = iNewVertex;
  264.             }
  265.  
  266.             // add normal contribution to every vertex with this rawVertexIndex and
  267.             // this smoothinggroup
  268.             AddNormalContribution(pMeshData, iRawVertexIndex, iSmoothingGroupIndex, pMesh->getFaceNormal(iFace));
  269.         }
  270.     }
  271.  
  272.     for (iVertex = 0; iVertex < pMeshData->m_cVertices; iVertex++)
  273.     {
  274.         pMeshData->m_rgVertices[iVertex].vNormal.Normalize();
  275.     }
  276.  
  277. e_Exit:
  278.     delete[] rgbVertexReferencedArray;
  279.  
  280.     return hr;
  281. }
  282.  
  283.  
  284.  
  285. BOOL FindIdenticalPatchVertex
  286.     (
  287.     SPatchMeshData *pPatchMeshData, 
  288.     DWORD iVertexIndex, 
  289.     DWORD iTextureIndex,
  290.     DWORD *piVertex
  291.     )
  292. {
  293.     DWORD iHeadVertex;
  294.     DWORD iCurVertex;
  295.  
  296.     // walk the wedge list to see if any of the other vertice have the same smoothing and texture index
  297.     iHeadVertex = iVertexIndex;
  298.     iCurVertex = iHeadVertex;
  299.     do
  300.     {
  301.         // if identical requirements, then return true with the vertex index
  302.         if (pPatchMeshData->m_rgVertices[iCurVertex].iTextureIndex == iTextureIndex)
  303.         {
  304.             *piVertex = iCurVertex;
  305.             return TRUE;
  306.         }
  307.  
  308.         // move to next element of wedge list and check to see if we wrapped (circular list)
  309.         iCurVertex = pPatchMeshData->m_rgVertices[iCurVertex].iWedgeList;
  310.     }
  311.     while (iHeadVertex != iCurVertex);
  312.  
  313.     return FALSE;
  314. }
  315.  
  316. HRESULT GeneratePatchMeshData
  317.     (
  318.     PatchMesh *pPatchMesh,
  319.     SPatchMeshData *pPatchMeshData 
  320.     )
  321. {
  322.     HRESULT hr = S_OK;
  323.     BYTE *rgbVertexReferencedArray = NULL;
  324.     DWORD cVerticesMax;
  325.     DWORD iRawVertexIndex;
  326.     DWORD iTextureIndex;
  327.     DWORD iVertex;
  328.     DWORD iPoint;
  329.     DWORD iNewVertex;
  330.     BOOL bFound;
  331.     SPatchVertexData *rgVerticesNew;
  332.     DWORD iCurVertex;
  333.     DWORD iPatch;
  334.     DWORD cPoints;
  335.     PatchVec *pvPatchVecs;
  336.     Patch *pPatch;
  337.     DWORD *rgdwControl;
  338.  
  339.     assert(pPatchMesh != NULL);
  340.     assert(pPatchMeshData != NULL);
  341.  
  342.     pPatchMeshData->m_bTexCoordsPresent = FALSE;
  343.     pPatchMeshData->m_cPatches = pPatchMesh->numPatches;
  344.  
  345.     // UNDONE - need to refine
  346.     cVerticesMax = pPatchMeshData->m_cPatches * 16;
  347.  
  348.     pPatchMeshData->m_rgVertices = new SPatchVertexData[cVerticesMax];
  349.     pPatchMeshData->m_rgPatches = new SPatchData[pPatchMesh->numPatches];
  350.  
  351.     if ((pPatchMeshData->m_rgVertices == NULL) 
  352.             || (pPatchMeshData->m_rgPatches == NULL))
  353.     {
  354.         hr = E_OUTOFMEMORY;
  355.         goto e_Exit;
  356.     }
  357.  
  358.     // initialize the verts being copied from the pPatchMesh->verts array
  359.     for (iVertex = 0; iVertex < pPatchMesh->numVerts; iVertex++)
  360.     {
  361.         pPatchMeshData->m_rgVertices[iVertex].vPosition = pPatchMesh->verts[iVertex].p;
  362.  
  363.         pPatchMeshData->m_rgVertices[iVertex].iPointRep = iVertex;
  364.         pPatchMeshData->m_rgVertices[iVertex].iWedgeList = iVertex;
  365.  
  366.         pPatchMeshData->m_rgVertices[iVertex].iTextureIndex = 0;
  367.     }
  368.  
  369.     // for the rest of vers, init the non position fields, position filled in when
  370.     //   reading patches
  371.     iCurVertex = pPatchMesh->numVerts;
  372.     for (iVertex = iCurVertex; iVertex < cVerticesMax; iVertex++)
  373.     {
  374.         pPatchMeshData->m_rgVertices[iVertex].iPointRep = iVertex;
  375.         pPatchMeshData->m_rgVertices[iVertex].iWedgeList = iVertex;
  376.  
  377.         pPatchMeshData->m_rgVertices[iVertex].iTextureIndex = 0;
  378.     }
  379.  
  380.  
  381.     pvPatchVecs = pPatchMesh->vecs;
  382.     for (iPatch = 0; iPatch < pPatchMesh->numPatches; iPatch++)
  383.     {
  384.         pPatch = &pPatchMesh->patches[iPatch];
  385.  
  386.         if (pPatch->type == PATCH_TRI)
  387.         {
  388.             // nControlIndices
  389.             pPatchMeshData->m_rgPatches[iPatch].m_cControl = 10;
  390.  
  391.             rgdwControl = pPatchMeshData->m_rgPatches[iPatch].m_rgdwControl;
  392.             rgdwControl[0] = pPatch->v[0];
  393.             rgdwControl[3] = pPatch->v[1];
  394.             rgdwControl[6] = pPatch->v[2];
  395.  
  396.             rgdwControl[1] = iCurVertex;
  397.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[0]].p;
  398.             iCurVertex += 1;
  399.         
  400.             rgdwControl[2] = iCurVertex;
  401.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[1]].p;
  402.             iCurVertex += 1;
  403.         
  404.             rgdwControl[4] = iCurVertex;
  405.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[2]].p;
  406.             iCurVertex += 1;
  407.         
  408.             rgdwControl[5] = iCurVertex;
  409.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[3]].p;
  410.             iCurVertex += 1;
  411.         
  412.             rgdwControl[7] = iCurVertex;
  413.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[4]].p;
  414.             iCurVertex += 1;
  415.         
  416.             rgdwControl[8] = iCurVertex;
  417.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[5]].p;
  418.             iCurVertex += 1;
  419.         
  420.             // UNDONE - is the correct way to get a single interior control
  421.             //  point from 3ds max
  422.             rgdwControl[9] = iCurVertex;
  423.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->interior[0]].p;
  424.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition += pvPatchVecs[pPatch->interior[1]].p;
  425.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition += pvPatchVecs[pPatch->interior[2]].p;
  426.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition /= 3;
  427.             iCurVertex += 1;
  428.         }
  429.         else if (pPatch->type == PATCH_QUAD)
  430.         {
  431.             // nControlIndices
  432.             pPatchMeshData->m_rgPatches[iPatch].m_cControl = 16;
  433.  
  434.             rgdwControl = pPatchMeshData->m_rgPatches[iPatch].m_rgdwControl;
  435.             rgdwControl[0] = pPatch->v[0];
  436.             rgdwControl[3] = pPatch->v[1];
  437.             rgdwControl[6] = pPatch->v[2];
  438.             rgdwControl[9] = pPatch->v[3];
  439.  
  440.             rgdwControl[1] = iCurVertex;
  441.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[0]].p;
  442.             iCurVertex += 1;
  443.         
  444.             rgdwControl[2] = iCurVertex;
  445.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[1]].p;
  446.             iCurVertex += 1;
  447.         
  448.             rgdwControl[4] = iCurVertex;
  449.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[2]].p;
  450.             iCurVertex += 1;
  451.         
  452.             rgdwControl[5] = iCurVertex;
  453.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[3]].p;
  454.             iCurVertex += 1;
  455.         
  456.             rgdwControl[7] = iCurVertex;
  457.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[4]].p;
  458.             iCurVertex += 1;
  459.         
  460.             rgdwControl[8] = iCurVertex;
  461.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[5]].p;
  462.             iCurVertex += 1;
  463.         
  464.             rgdwControl[10] = iCurVertex;
  465.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[6]].p;
  466.             iCurVertex += 1;
  467.  
  468.             rgdwControl[11] = iCurVertex;
  469.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->vec[7]].p;
  470.             iCurVertex += 1;
  471.  
  472.             rgdwControl[12] = iCurVertex;
  473.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->interior[0]].p;
  474.             iCurVertex += 1;
  475.  
  476.             rgdwControl[13] = iCurVertex;
  477.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->interior[1]].p;
  478.             iCurVertex += 1;
  479.  
  480.             rgdwControl[14] = iCurVertex;
  481.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->interior[2]].p;
  482.             iCurVertex += 1;
  483.  
  484.             rgdwControl[15] = iCurVertex;
  485.             pPatchMeshData->m_rgVertices[iCurVertex].vPosition = pvPatchVecs[pPatch->interior[3]].p;
  486.             iCurVertex += 1;
  487.         }
  488.         else // undefined patch type
  489.         {
  490.             hr = E_INVALIDARG;
  491.             goto e_Exit;
  492.         }
  493.     }
  494.  
  495.     // now record the initial number of vertices
  496.     pPatchMeshData->m_cVerticesBeforeDuplication = iCurVertex;
  497.     pPatchMeshData->m_cVertices = iCurVertex;
  498.  
  499.     rgbVertexReferencedArray = new BYTE[pPatchMeshData->m_cVertices];
  500.     if (rgbVertexReferencedArray == NULL)
  501.     {
  502.         hr = E_OUTOFMEMORY;
  503.         goto e_Exit;
  504.     }
  505.     memset(rgbVertexReferencedArray, 0, sizeof(BYTE) * pPatchMeshData->m_cVertices);
  506.  
  507.     for( iPatch = 0; iPatch < pPatchMeshData->m_cPatches; iPatch++ )
  508.     {
  509.         cPoints = (pPatchMeshData->m_rgPatches[iPatch].m_cControl == 10) ? 3 : 4;
  510.         for( iPoint = 0; iPoint < cPoints; iPoint++ ) 
  511.         {
  512.             iTextureIndex = 0xFFFFFFFF;
  513.             iRawVertexIndex = pPatchMeshData->m_rgPatches[iPatch].m_rgdwControl[iPoint * 3];
  514.  
  515.             // try to get a texture index
  516.             if ((pPatchMesh->tvPatches.Count() >= 2) && (pPatchMesh->tvPatches[1] != NULL))
  517.             {
  518.                 iTextureIndex = pPatchMesh->tvPatches[1][iPatch].tv[iPoint];
  519.                 if (iTextureIndex < pPatchMesh->numTVerts[1])
  520.                 {
  521.                     pPatchMeshData->m_bTexCoordsPresent = TRUE;
  522.                 }
  523.                 else
  524.                 {
  525.                     iTextureIndex = 0xFFFFFFFF;
  526.                 }
  527.             }
  528.  
  529.             if (rgbVertexReferencedArray[iRawVertexIndex] == FALSE)
  530.             {
  531.                 // first reference to this vertex.
  532.                 rgbVertexReferencedArray[iRawVertexIndex] = TRUE;
  533.  
  534.                 pPatchMeshData->m_rgVertices[iRawVertexIndex].iTextureIndex = iTextureIndex;
  535.             }
  536.             else
  537.             {
  538.                 // need to remember the index
  539.                 bFound = FindIdenticalPatchVertex(pPatchMeshData, iRawVertexIndex, iTextureIndex, &iNewVertex);
  540.  
  541.                 // if not found, then split out another vertex
  542.                 if (!bFound)
  543.                 {
  544.                     // realloc if array too small
  545.                     if (pPatchMeshData->m_cVertices == cVerticesMax)
  546.                     {
  547.                         cVerticesMax = cVerticesMax * 2;
  548.                         rgVerticesNew = new SPatchVertexData[cVerticesMax];
  549.                         if (rgVerticesNew == NULL)
  550.                         {
  551.                             hr = E_OUTOFMEMORY;
  552.                             goto e_Exit;
  553.                         }
  554.  
  555.                         memcpy(rgVerticesNew, pPatchMeshData->m_rgVertices, sizeof(SPatchVertexData) * pPatchMeshData->m_cVertices);
  556.  
  557.                         delete []pPatchMeshData->m_rgVertices;
  558.                         pPatchMeshData->m_rgVertices = rgVerticesNew;
  559.                     }
  560.  
  561.                     // grab the next spot in the array
  562.                     iNewVertex = pPatchMeshData->m_cVertices;
  563.                     pPatchMeshData->m_cVertices += 1;
  564.  
  565.                     // setup point rep and wedge list
  566.                     pPatchMeshData->m_rgVertices[iNewVertex].iPointRep = iRawVertexIndex;
  567.  
  568.                     // link into wedge list of point rep
  569.                     pPatchMeshData->m_rgVertices[iNewVertex].iWedgeList = pPatchMeshData->m_rgVertices[iRawVertexIndex].iWedgeList;
  570.                     pPatchMeshData->m_rgVertices[iRawVertexIndex].iWedgeList = iNewVertex;
  571.  
  572.                     // setup vertex info
  573.                     pPatchMeshData->m_rgVertices[iNewVertex].vPosition = pPatchMeshData->m_rgVertices[iRawVertexIndex].vPosition;
  574.                     pPatchMeshData->m_rgVertices[iNewVertex].iTextureIndex = iTextureIndex;
  575.                 }
  576.  
  577.                 // update the control point to the new vertex position
  578.                 pPatchMeshData->m_rgPatches[iPatch].m_rgdwControl[iPoint * 3] = iNewVertex;
  579.             }
  580.         }
  581.  
  582.     }
  583.  
  584. e_Exit:
  585.     delete []rgbVertexReferencedArray;
  586.  
  587.     return hr;
  588. }